#pragma once
#ifndef DYNAMICDATA_H
#define DYNAMICDATA_H

/// Vlare does not use RTTI


#ifndef NOSTDAFX
#include "StdAfx.h"
#endif

#include "Hook.h"


#ifndef NOTYPECHECK
#include <assert.h>
#define VLARE_TYPECHECK(dd,t) assert((dd)->type==DynamicData::t || (dd)->type==DynamicData::TYPE_FUNCTION)
#else
#define VLARE_TYPECHECK(dd,t)
#endif

#define VLARE_INVOKEGET(dd,typnam,memnam,typ) (((dd)->type==DynamicData::typnam)?(dd)->val.memnam:(typ)(dd)->val.pfn(0x0, VlareHashMap(), 0x0))

/////could cause perfomance penalty because of bigger union-size
//#define VLARE_ENABLE_HASHMAP_TYPE

struct CostumeMatrix;
struct CostumeRenderData;

/// define the desired floatingpoint-type for Vlare
#ifndef _Vloat
#define _Vloat double
#endif

struct DynamicData;


typedef _Vloat Vloat;

/// A VlareFunctionCall can be called by anyone
typedef DynamicData (*VlareFunctionCall)(DynamicData& params);

/// A VlareFunction is the one to implement and register
/**
 * A call to a VlareFunction is wrapped by a Hook. Element and property-ame data is passed on.
 **/
typedef DynamicData (*VlareFunction)(const Hook *const hook,/*  DynamicData& params,*/ VlareHashMap& upvalues, DynamicData ...);


struct DynamicData
{
	//bool isResponsibleForMemory=true; //<if the dd is a pointer, coord2d, array or hashmap it will free it on destruction
	enum VLARE_TYPE {
		TYPE_STRING,	//<Text
		TYPE_INT,		//<Integral type
		TYPE_FLOAT,		//<Floatingpointvalue (can also be double)
		TYPE_COORD1D,	//<todo
		TYPE_COORD2D,	//<todo
		TYPE_MATRIX,	//<todo
		TYPE_ELEMENT,	//<todo: needed?
		TYPE_POINTER,	//<Pointer
		TYPE_ARRAY,		//<a field of DynamicData(s) and a trailing 
		TYPE_HASHMAP,	//<a Hashmap (if this is enabled during compilation)
		TYPE_FUNCTION,	//<a Function, taking DynamicData as a parameter and returns a DynamicData. If param is null -> get; param is TYPE_XXX ->set
		TYPE_NOTIFY,	//<dummy for Dataless Notification this can be returned by VlareFunctions when invoked. Moreover this can be directly the Value of an event, more then one Function (Listener) can be invoked then via Hooks.
		TYPE_NOT_SET,
		TYPE_NULL		//<Beware: This is the type. There is a difference to TYPE_POINTER and _dynDat==null!
	} type;
	/**
	 * If the content is a VlareFunction, there is a recursion
	 *  DynamicData > _dynDat > VlareFunction > DynamicData
	 */
	union _dynDat {
		const char* szVal;
		int iVal;
		Vloat dVal;
		void* pVal;
	#ifdef VLARE_ENABLE_ARRAY_TYPE
		/// arrays must be malloced, they are freed by Vlare-core when not longer needed
		DynamicData* aVal;
	#endif
	#ifdef VLARE_ENABLE_HASHMAP_TYPE
		vlareHashMap map;
	#endif
		VlareFunction pfn;

		_dynDat(const char* szVal);
		_dynDat(int iVal);
		_dynDat(Vloat dVal);
		_dynDat(void* pVal);
		_dynDat(DynamicData* aVal);
		_dynDat(VlareFunction pfnVal);
		_dynDat(const _dynDat& val);
	} val;
	DynamicData();
	DynamicData(const char* const val);
	DynamicData(int val);
	DynamicData(Vloat val);
	DynamicData(void* val);
	DynamicData(DynamicData* allocatedArray);
	DynamicData(VlareFunction val);
	DynamicData(const DynamicData& val);
	
	operator const char* () const;
	operator int () const;
	operator Vloat () const;
	operator void* () const;
	//operator DynamicData* () const;
	operator VlareFunction () const;
	DynamicData operator()(const DynamicData* aVal);
	//DynamicData& operator= (const DynamicData& );
	~DynamicData(void);
};
#endif
